﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="NetImage.cs" company="">
//   
// </copyright>
// <summary>
//   The net image.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Drawing
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;

    using Libium.Core;

    /// <summary>
    /// The net image.
    /// </summary>
    public class NetImage : IImage
    {
        #region Fields

        /// <summary>
        /// The _image.
        /// </summary>
        private readonly Image _image;

        /// <summary>
        /// The _file.
        /// </summary>
        private IFile _file;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="NetImage"/> class.
        /// </summary>
        /// <param name="image">
        /// The image.
        /// </param>
        public NetImage(Image image)
            : this(image, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NetImage"/> class.
        /// </summary>
        /// <param name="stream">
        /// The stream.
        /// </param>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <exception cref="NotSupportedException">
        /// </exception>
        public NetImage(Stream stream, ImageStreamType type = ImageStreamType.Bitmap)
        {
            if (type == ImageStreamType.Bitmap)
            {
                var memoryStream = stream.CopyToMemoryStream();

                // Stream used in Image constructor must be opened during image lifetime
                _image = Image.FromStream(memoryStream);
            }
            else if (type == ImageStreamType.DeviceIndependentBitmap)
            {
                _image = ImageUtility.DibStreamToImage(stream);
            }
            else
            {
                throw new NotSupportedException("Unknown image type");
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NetImage"/> class.
        /// </summary>
        /// <param name="file">
        /// The file.
        /// </param>
        public NetImage(IFile file)
            : this(file.GetReadStream(), ImageStreamType.Bitmap)
        {
            _file = file;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NetImage"/> class.
        /// </summary>
        /// <param name="filePath">
        /// The file path.
        /// </param>
        public NetImage(string filePath)
            : this(new LocalFile(filePath))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NetImage"/> class.
        /// </summary>
        /// <param name="uri">
        /// The uri.
        /// </param>
        public NetImage(Uri uri)
            : this(new UriFile(uri))
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="NetImage"/> class.
        /// </summary>
        /// <param name="image">
        /// The image.
        /// </param>
        /// <param name="file">
        /// The file.
        /// </param>
        private NetImage(Image image, IFile file)
        {
            _image = image;
            _file = file;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the mime type.
        /// </summary>
        public MimeType MimeType
        {
            get
            {
                return ImageUtility.GetMimeType(_image.RawFormat);
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The get file.
        /// </summary>
        /// <returns>
        /// The <see cref="IFile"/>.
        /// </returns>
        public IFile GetFile()
        {
            if (_file == null)
            {
                using (var stream = GetStream())
                {
                    _file = new MemoryFile(null, MimeType.FileExtensions.First(), stream);
                }
            }

            return _file;
        }

        /// <summary>
        /// The get stream.
        /// </summary>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <returns>
        /// The <see cref="Stream"/>.
        /// </returns>
        public Stream GetStream(ImageStreamType type = ImageStreamType.Bitmap)
        {
            var stream = new MemoryStream();
            _image.Save(stream, Equals(_image.RawFormat, ImageFormat.MemoryBmp) ? ImageFormat.Png : _image.RawFormat);
            stream.Position = 0;
            return stream;
        }

        #endregion
    }
}